/**
 * 
 */
package rmitut;

import java.net.InetAddress;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.logging.Logger;

/**
 * @author michele
 *
 */
public class CommunicationServer extends UnicastRemoteObject 
	implements CommunicationServerRemoteAPI {
	
	private static final long serialVersionUID = 2028392788640926244L;

	private static  CommunicationServer comServer = null;
	
	private final Integer rmiregistryLocalPort = 1099;
	private String serviceNodeName="NetworkNode";

	private Deque<Message> receivedMessages;
	
	private Logger logger;
	
	protected CommunicationServer(Deque<Message> msgQueue) throws RemoteException {
		super();
		this.receivedMessages = msgQueue;
		logger = Logger.getLogger(CommunicationServer.class.getName());
	}
	
	public static CommunicationServer getComunicationServer(Deque<Message> msgQueue){
		if(comServer == null){
			try {
				comServer = new CommunicationServer(msgQueue);
			} catch (RemoteException e) {
				e.printStackTrace();
			}
		}
		return comServer;
	}

	public void registryToRmiregistry() throws RemoteException{
		registryToRmiregistry(serviceNodeName);
	}
	
	public void registryToRmiregistry(String parName) throws RemoteException  {
		System.out.println("Creating the ComunicationServer..");
		
		Registry registry;
		CommunicationServerRemoteAPI remoteObject_stub;		
		if (comServer != null) {
			if (System.getSecurityManager() == null) {
				System.setSecurityManager(new SecurityManager());
			}
			UnicastRemoteObject.unexportObject(comServer, true);
			remoteObject_stub = (CommunicationServerRemoteAPI) UnicastRemoteObject.exportObject(comServer, 0);
			String name = parName;
			try {
				System.out.println("Using an existing rmiregistry");
				registry = LocateRegistry.getRegistry(rmiregistryLocalPort.intValue());				
				registry.rebind(name, remoteObject_stub);
			} catch (java.rmi.ConnectException e) {
				System.out.println("Failed!\nTrying to create a new registry");
				registry = LocateRegistry.createRegistry(rmiregistryLocalPort
						.intValue());
				registry.rebind(name, remoteObject_stub);
				System.out.println("done");
			}
			System.out.println("Services registered to rmiregistry on port: "+registry.REGISTRY_PORT);
			for(String s : registry.list())
				System.out.println("- "+s);
		}else{
			System.err.println("Uninitialized ComunicationServer");
		}
	}

	@Override
	public boolean receiveMessage(Message m) throws RemoteException {
		boolean ret = false;
		synchronized (receivedMessages) {
			ret = receivedMessages.add(m);
			receivedMessages.notify();
		}
		logger.info("received message "+m);
		return ret;
	}

	@Override
	public boolean sendMessage(Message m, InetAddress host, String service) throws RemoteException {
		boolean ret = false;
		Registry registry = LocateRegistry.getRegistry(host.getHostAddress());
		try {
			CommunicationServerRemoteAPI hostServer = 
				(CommunicationServerRemoteAPI) registry.lookup(service);
			hostServer.receiveMessage(m);
			logger.info("sent message to "+ host);
			ret = true;
		} catch (NotBoundException e) {
			e.printStackTrace();
		}
		return ret;
	}

}
